package com.jzo2o.health.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.dto.response.NativePayResDTO;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.constants.MqConstants;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.IdUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.*;
import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.model.dto.request.OrdersPageQueryReqDTO;
import com.jzo2o.health.model.dto.request.PlaceOrderReqDTO;
import com.jzo2o.health.model.dto.response.*;
import com.jzo2o.health.properties.TradeProperties;
import com.jzo2o.health.service.*;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.rabbitmq.client.RabbitClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 22096
* @description 针对表【orders(订单表)】的数据库操作Service实现
* @createDate 2024-12-14 15:39:08
*/
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders>
    implements OrdersService{

    @Autowired
    private ISetmealService setmealService;

    @Autowired
    private IUserService userService;

    @Autowired
    private NativePayApi nativePayApi;

    @Autowired
    private RabbitClient rabbitClient;
    /**
     * 下单接口
     * @param placeOrderReqDTO
     * @return
     */
    @Override
    public PlaceOrderResDTO place(PlaceOrderReqDTO placeOrderReqDTO) {
        Orders orders = BeanUtils.copyBean(placeOrderReqDTO, Orders.class);
        PlaceOrderResDTO placeOrderResDTO = new PlaceOrderResDTO();
        LambdaQueryWrapper<Orders> eq = Wrappers.<Orders>lambdaQuery().eq(Orders::getCheckupPersonIdcard, orders.getCheckupPersonIdcard()).eq(Orders::getSetmealId, orders.getSetmealId()).eq(Orders::getReservationDate, orders.getReservationDate());
        Orders order = this.getOne(eq);
        if (ObjectUtils.isNotNull(order)){
            placeOrderResDTO = new PlaceOrderResDTO();
            placeOrderResDTO.setId(order.getId());
            return placeOrderResDTO;
        }
        Setmeal setmeal = setmealService.getById(placeOrderReqDTO.getSetmealId());
        if (ObjectUtils.isNull(setmeal)){
            throw new CommonException("没有此套餐");
        }
        orders.setOrderStatus(OrderStatusEnum.NO_PAY.getStatus());
        orders.setPayStatus(OrderPayStatusEnum.NO_PAY.getStatus());
        orders.setSetmealName(setmeal.getName());
        orders.setSetmealSex(setmeal.getSex());
        orders.setSetmealAge(setmeal.getAge());
        orders.setSetmealImg(setmeal.getImg());
        orders.setSetmealRemark(setmeal.getRemark());
        orders.setSetmealPrice(BigDecimal.valueOf(setmeal.getPrice()));
        orders.setMemberId(1674350264389750786L);
        User user = userService.getById(1674350264389750786L);
        if (ObjectUtils.isNull(user)){
            throw new CommonException("用户不存在");
        }
        orders.setMemberPhone(user.getPhone());
        boolean save = this.save(orders);
        if (!save){
            throw new DBException("操作失败");
        }
        placeOrderResDTO.setId(orders.getId());
        return placeOrderResDTO;
    }

    @Autowired
    private TradeProperties tradeProperties;
    @Autowired
    private OrdersService ordersService;
    @Autowired
    private TradingApi tradingApi;
    @Autowired
    private OrdersCancelledService ordersCancelledService;
    /**
     * 订单支付
     * @param id
     * @param tradingChannel
     * @return
     */
    @Override
    public OrdersPayResDTO pay(Long id, PayChannelEnum tradingChannel) {
        Orders orders = this.getById(id);
        if (ObjectUtils.isNull(orders)){
            throw new CommonException("订单不存在");
        }
        //判断订单是否已支付成功（支付状态和交易单号）
        if (ObjectUtils.equals(orders.getPayStatus(), OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                && ObjectUtils.isNotNull(orders.getTradingOrderNo())) {
            OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
            ordersPayResDTO.setProductOrderNo(id);
            return ordersPayResDTO;
        }
        //根据支付渠道获取商户号
        Long enterpriseId = ObjectUtils.equals(tradingChannel, PayChannelEnum.WECHAT_PAY) ? tradeProperties.getWechatEnterpriseId()
                : tradeProperties.getAliEnterpriseId();
        //判断是否更换过支付渠道 （订单已有支付渠道，且与本次请求参数的支付渠道不一样，就算更换过）
        boolean changeChannel = false; //默认值：未更换
        if (ObjectUtils.isNotNull(orders.getTradingChannel()) && ObjectUtils.notEqual(orders.getTradingChannel(), tradingChannel)) {
            changeChannel = true;
        }
        //业务系统唯一标识
        String productAppId = tradeProperties.getProductAppId();

        NativePayReqDTO nativePayReqDTO = new NativePayReqDTO();
        nativePayReqDTO.setTradingAmount(new BigDecimal(0.01));
        nativePayReqDTO.setEnterpriseId(enterpriseId);
        Setmeal setmeal = setmealService.getById(orders.getSetmealId());
        nativePayReqDTO.setMemo(setmeal.getName());
        nativePayReqDTO.setProductAppId(productAppId);
        nativePayReqDTO.setProductOrderNo(id);
        nativePayReqDTO.setTradingChannel(tradingChannel);
        nativePayReqDTO.setChangeChannel(changeChannel);
        NativePayResDTO downLineTrading = nativePayApi.createDownLineTrading(nativePayReqDTO);
        if (ObjectUtils.isNull(downLineTrading)) {
            throw new BadRequestException("调用支付服务的支付接口失败");
        }
        ordersService.updateOrders(id,downLineTrading);
        //5. 封装响应数据
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(downLineTrading, OrdersPayResDTO.class);
        ordersPayResDTO.setPayStatus(orders.getPayStatus());
        return ordersPayResDTO;
    }

    /**
     * 更新支付订单状态
     * @param orderId
     * @param nativePayResDTO
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateOrders(Long orderId, NativePayResDTO nativePayResDTO) {
        boolean result = this.lambdaUpdate().eq(Orders::getId, orderId)
                .set(Orders::getTradingChannel, nativePayResDTO.getTradingChannel())
                .set(Orders::getTradingOrderNo, nativePayResDTO.getTradingOrderNo())
                .update();
        if (!result) {
            throw new DBException("支付失败");
        }
    }

    /**
     * 查询订单支付结果
     * @param id
     * @return
     */
    @Override
    public OrdersPayResDTO payResult(Long id) {
        Orders orders = this.getById(id);
        if (ObjectUtils.isNull(orders)){
            throw new CommonException("订单不存在");
        }
        //判断是否有交易单号
        if(ObjectUtils.isNull(orders.getTradingOrderNo())) {
            throw new BadRequestException("非法订单");
        }
        //判断是否支付成功
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
        ordersPayResDTO.setProductOrderNo(orders.getId());
        if (ObjectUtils.equals(orders.getPayStatus(),OrderPayStatusEnum.PAY_SUCCESS.getStatus())){
            return ordersPayResDTO;
        }
        //调用查询支付是否成功接口
        TradingResDTO tradResultByTradingOrderNo = tradingApi.findTradResultByTradingOrderNo(orders.getTradingOrderNo());
        //更新订单表信息（支付时间、第三方交易号、订单状态、支付状态）
        if(ObjectUtils.isNotNull(tradResultByTradingOrderNo) && ObjectUtils.equals(tradResultByTradingOrderNo.getTradingState(), TradingStateEnum.YJS)) {
            ordersService.paySuccess(id,tradResultByTradingOrderNo.getTransactionId(), LocalDateTime.now());
            ordersPayResDTO.setQrCode(tradResultByTradingOrderNo.getQrCode());
            ordersPayResDTO.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());//支付成功
        }
//        rabbitClient.sendMsg(MqConstants.Exchanges.TRADE,
//                MqConstants.RoutingKeys.TRADE_UPDATE_STATUS,
//                orders.getId(),
//                60000,
//                IdUtils.getSnowflakeNextId(),
//                false);
        return ordersPayResDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void paySuccess(Long orderId,String transactionId,LocalDateTime payTime){
        boolean update = this.lambdaUpdate()
                .eq(Orders::getId, orderId)
                .set(Orders::getOrderStatus,OrderStatusEnum.WAITING_CHECKUP.getStatus())
                .set(Orders::getPayStatus,OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .set(Orders::getTransactionId, transactionId)
                .set(Orders::getPayTime, payTime).update();
        if (!update) {
            throw new DBException("更新失败");
        }
    }

    /**
     * 订单取消
     * @param dto
     */
    @Override
    public void cancel(OrdersCancelReqDTO dto) {
        Orders orders = this.getById(dto.getId());
        if (ObjectUtils.isNull(orders)){
            throw new CommonException("订单不存在");
        }
        if (orders.getOrderStatus().equals(OrderStatusEnum.NO_PAY.getStatus()) && orders.getTransactionId()==null){
            OrdersCancelled ordersCancelled1 = ordersCancelledService.getById(dto.getId());
            if (ObjectUtils.isNotNull(ordersCancelled1)){
                throw new CommonException("订单已取消");
            }
            OrdersCancelled ordersCancelled = new OrdersCancelled();
            ordersCancelled.setCancellerId(UserThreadLocal.currentUserId());
            ordersCancelled.setCancellerName(UserThreadLocal.currentUser().getName());
            ordersCancelled.setCancellerType(1);
            ordersCancelled.setCancelReason(dto.getCancelReason());
            ordersCancelled.setId(dto.getId());
            ordersCancelled.setCancelTime(LocalDate.now());
            ordersService.updateOrdersForCancel(dto,ordersCancelled);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateOrdersForCancel(OrdersCancelReqDTO dto,OrdersCancelled ordersCancelled) {
        boolean save = ordersCancelledService.save(ordersCancelled);
        if (!save){
            throw new DBException("操作失败");
        }
        boolean update = this.lambdaUpdate().eq(Orders::getId, dto.getId()).set(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus()).update();
        if (!update) {
            throw new DBException("操作失败");
        }
    }

    @Autowired
    private RefundRecordApi refundRecordApi;
    @Autowired
    private OrdersRefundService ordersRefundService;
    /**
     * 订单退款
     * @param dto
     */
    @Override
    public void refund(OrdersCancelReqDTO dto) {
        Orders orders = this.getById(dto.getId());
        if (ObjectUtils.isNull(orders)){
            throw new CommonException("订单不存在");
        }
        if (ObjectUtils.isNull(orders.getTransactionId())){
            throw new CommonException("订单不合法");
        }
        ExecutionResultResDTO executionResultResDTO = refundRecordApi.refundTrading(orders.getTradingOrderNo(), BigDecimal.valueOf(0.01));
        if (RefundStatusEnum.SENDING.getCode().equals(executionResultResDTO.getRefundStatus())){
            executionResultResDTO=refundRecordApi.refundTrading(orders.getTradingOrderNo(), BigDecimal.valueOf(0.01));
        }
        OrdersRefund ordersRefund = ordersRefundService.getById(orders.getId());
        if (ObjectUtils.isNotNull(ordersRefund)){
            throw new CommonException("订单无法退款或已退款");
        }
        if (RefundStatusEnum.SUCCESS.getCode().equals(executionResultResDTO.getRefundStatus())){
            OrdersRefund ordersRefund1 = new OrdersRefund();
            ordersRefund1.setId(orders.getId());
            ordersRefund1.setRealPayAmount( BigDecimal.valueOf(0.01));
            ordersRefund1.setTradingOrderNo(Long.valueOf(executionResultResDTO.getRefundNo()));
            ordersService.updateForRefund(ordersRefund1,executionResultResDTO,orders);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateForRefund(OrdersRefund ordersRefund1,ExecutionResultResDTO executionResultResDTO,Orders orders){
        boolean save = ordersRefundService.save(ordersRefund1);
        if (!save){
            throw new DBException("操作失败");
        }
        boolean update = ordersService.lambdaUpdate().set(Orders::getRefundId, executionResultResDTO.getRefundId())
                .set(Orders::getRefundNo, executionResultResDTO.getRefundNo())
                .set(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.REFUND_SUCCESS.getStatus())
                .eq(Orders::getId, orders.getId()).update();
        if (!update){
            throw new DBException("操作失败");
        }
    }

    /**
     * 滚动分页查询
     * @param ordersStatus
     * @param sortBy
     * @return
     */
    @Override
    public List<OrdersResDTO> pageQuery(Integer ordersStatus, Long sortBy) {
        List<Orders> list = this.lambdaQuery().eq(ObjectUtils.isNotEmpty(ordersStatus), Orders::getOrderStatus, ordersStatus)
                .eq(ObjectUtils.isNotEmpty(sortBy), Orders::getSortBy, sortBy).list();
        if (CollUtils.isEmpty(list)){
            throw new CommonException("集合为空");
        }
        List<OrdersResDTO> ordersResDTOS = list.stream().map(s -> {
            OrdersResDTO ordersResDTO = new OrdersResDTO();
            BeanUtils.copyProperties(s, ordersResDTO);
            return ordersResDTO;
        }).collect(Collectors.toList());
        if (CollUtils.isEmpty(ordersResDTOS)){
            throw new CommonException("集合为空");
        }
        return ordersResDTOS;
    }

    /**
     * 根据订单id查询
     * @param id
     * @return
     */
    @Override
    public OrdersDetailResDTO detail(Long id) {
        Orders orders = this.getById(id);
        if (ObjectUtils.isNull(orders)){
            throw new CommonException("订单不存在");
        }
        OrdersDetailResDTO ordersDetailResDTO = BeanUtils.copyBean(orders, OrdersDetailResDTO.class);
        if (ObjectUtils.isNull(ordersDetailResDTO)){
            throw new CommonException("订单不存在");
        }
        return ordersDetailResDTO;
    }

    /**
     * 管理端订单分页查询
     * @param dto
     * @return
     */
    @Override
    public PageResult<OrdersResDTO> adminPageQuery(OrdersPageQueryReqDTO dto) {
        IPage page=new Page();
        page.setCurrent(dto.getPageNo());
        page.setSize(dto.getPageSize());
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery().eq(ObjectUtils.isNotEmpty(dto.getOrderStatus()), Orders::getOrderStatus, dto.getOrderStatus())
                .likeRight(ObjectUtils.isNotEmpty(dto.getMemberPhone()), Orders::getMemberPhone, dto.getMemberPhone());
//                .eq(ObjectUtils.isNotEmpty(dto.getIsAsc1()), Orders::getSortBy, dto.getIsAsc1())
//                .eq(ObjectUtils.isNotEmpty(dto.getIsAsc2()), Orders::getSortBy, dto.getIsAsc2())
//                .eq(ObjectUtils.isNotEmpty(dto.getOrderBy1()), Orders::getSortBy, dto.getOrderBy1())
//                .eq(ObjectUtils.isNotEmpty(dto.getOrderBy2()), Orders::getSortBy, dto.getOrderBy2());
        IPage page1 = this.page(page, queryWrapper);
        PageResult<OrdersResDTO> objectPageResult = new PageResult<>();
        objectPageResult.setList(page1.getRecords());
        objectPageResult.setPages(page1.getPages());
        objectPageResult.setTotal(page1.getTotal());
        return objectPageResult;
    }

    /**
     * 根据状态统计数量
     * @return
     */
    @Override
    public OrdersCountResDTO countByStatus() {
//        this.lambdaQuery().select().in(Orders::getOrderStatus,
//                OrderStatusEnum.CLOSED.getStatus(),
//                OrderStatusEnum.NO_PAY.getStatus(),
//                OrderStatusEnum.WAITING_CHECKUP.getStatus(),
//                OrderStatusEnum.COMPLETED_CHECKUP.getStatus(),
//                OrderStatusEnum.CANCELLED.getStatus()
//        ).count();
        Integer noPay = this.lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus()).count();
        Integer close = this.lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus()).count();
        Integer wCheckUp = this.lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.WAITING_CHECKUP.getStatus()).count();
        Integer completed = this.lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.COMPLETED_CHECKUP.getStatus()).count();
        Integer cancel = this.lambdaQuery().eq(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus()).count();
        Integer total = this.lambdaQuery().count();
        OrdersCountResDTO ordersCountResDTO = new OrdersCountResDTO();
        ordersCountResDTO.setCancelledCount(cancel);
        ordersCountResDTO.setTotalCount(total);
        ordersCountResDTO.setNoPayCount(noPay);
        ordersCountResDTO.setClosedCount(close);
        ordersCountResDTO.setWaitingCheckupCount(wCheckUp);
        ordersCountResDTO.setCompletedCheckupCount(completed);
        return ordersCountResDTO;
    }

    /**
     * 根据订单id查询
     * @param id
     * @return
     */
    @Override
    public AdminOrdersDetailResDTO aggregation(Long id) {
        OrdersCancelled ordersCancelled = ordersCancelledService.getById(id);
        if (ObjectUtils.isNull(ordersCancelled)){
            throw new CommonException("订单不存在");
        }
        Orders orders = ordersService.getById(id);
        OrdersRefund ordersRefund = ordersRefundService.getById(id);
        AdminOrdersDetailResDTO adminOrdersDetailResDTO = new AdminOrdersDetailResDTO();
        AdminOrdersDetailResDTO.CancelInfo cancelInfo = new AdminOrdersDetailResDTO.CancelInfo();
        AdminOrdersDetailResDTO.OrderInfo orderInfo = new AdminOrdersDetailResDTO.OrderInfo();
        AdminOrdersDetailResDTO.PayInfo payInfo = new AdminOrdersDetailResDTO.PayInfo();
        AdminOrdersDetailResDTO.RefundInfo refundInfo = new AdminOrdersDetailResDTO.RefundInfo();
        BeanUtils.copyProperties(orders, orderInfo);
        BeanUtils.copyProperties(orders, payInfo);
        BeanUtils.copyProperties(orders, refundInfo);
        BeanUtils.copyProperties(ordersRefund, refundInfo);
        cancelInfo.setCancelReason(ordersCancelled.getCancelReason());
        cancelInfo.setCancelTime(ordersCancelled.getCancelTime().atStartOfDay());
        adminOrdersDetailResDTO.setCancelInfo(cancelInfo);
        adminOrdersDetailResDTO.setOrderInfo(orderInfo);
        adminOrdersDetailResDTO.setPayInfo(payInfo);
        adminOrdersDetailResDTO.setRefundInfo(refundInfo);
        return adminOrdersDetailResDTO;
    }
}




